# -*- coding: utf-8 -*-
import binascii
import time

from tablestore import *

from Crypto import Random
from Crypto.Cipher import AES
from GKModel.BaseModel import BaseModel


class Staff(BaseModel):
    GID_BETA_OFFSET = 0
    GID_PREV_OFFSET = 100
    GID_PROD_OFFSET = 200
    SECRET = b'H8BgWv08QIvwGhJw'
    TABLE_NAME = 'Staffs'

    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def search_staff(self, account, password):
        inclusive_start_primary_key = [('account', account), ('uid', INF_MIN)]
        exclusive_end_primary_key = [('account', account), ('uid', INF_MAX)]
        columns_to_get = ['create_time', 'update_time']
        column_condition = SingleColumnCondition('password', password, ComparatorType.EQUAL)

        consumed, next_start_primary_key, row_list, next_token = self.ots_client.get_range(
            table_name=Staff.TABLE_NAME,
            direction=Direction.FORWARD,
            inclusive_start_primary_key=inclusive_start_primary_key,
            exclusive_end_primary_key=exclusive_end_primary_key,
            columns_to_get=columns_to_get,
            limit=1,
            column_filter=column_condition,
            max_version=1
        )

        if row_list is None or len(row_list) == 0:
            raise ValueError(1000004, 'No Such Staff')

        primary_key = dict(row_list[0].primary_key)
        account = primary_key['account']
        uid = primary_key['uid']
        data = {}

        for item in row_list[0].attribute_columns:
            data[item[0]] = item[1]

        data['account'] = account

        return account, uid, data

    @staticmethod
    def __make_token(account, uid):
        expired = int(time.time())
        plain = ','.join([account, str(uid), str(expired)]).encode()
        iv = Random.new().read(AES.block_size)
        cipher = AES.new(Staff.SECRET, AES.MODE_CFB, iv)
        token = iv + cipher.encrypt(plain)
        return binascii.b2a_base64(token, newline=False).decode()

    def __update_token(self, tok, account, uid):
        primary_key = [('account', account), ('uid', uid)]
        update_of_attribute_columns = {
            'PUT': [('token', tok)]
        }
        row = Row(primary_key, update_of_attribute_columns)
        condition = Condition(RowExistenceExpectation.IGNORE)
        consumed, return_row = self.ots_client.update_row(Staff.TABLE_NAME, row, condition)

    def update_token(self, account, uid):
        token = self.__make_token(account, uid)
        self.__update_token(token, account, uid)
        return token

    @staticmethod
    def __parse_token(staff_token):
        e = binascii.a2b_base64(staff_token)
        iv = e[:16]
        cipher = AES.new(Staff.SECRET, AES.MODE_CFB, iv)
        d = cipher.decrypt(e[16:]).decode()
        d_array = str.split(d, ',')
        return d_array


def new(**kwargs) -> Staff:
    return Staff(**kwargs)
